package com.cskaoyan.aspect;

import com.cskaoyan.bean.MarketAdmin;
import com.cskaoyan.bean.MarketLog;
import com.cskaoyan.bean.MarketOrder;
import com.cskaoyan.bean.bo.AdminOrderShipBO;
import com.cskaoyan.bean.common.BaseRespVo;
import com.cskaoyan.mapper.MarketLogMapper;
import com.cskaoyan.service.AdminLogService;
import jdk.net.SocketFlow;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MemberSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * @author gatsby
 * @since 2022/10/12 16:20
 */
@Component
@Aspect
public class AdminAspect {
    @Autowired
    AdminLogService adminLogService;

    @Pointcut("execution(* com.cskaoyan.controller..*(..))")
    private void pointCut(){
    }

    /**
     * @description 思路：获取成员变量，挨个赋值，然后insert
     * @param pjp
     * @return Object
     * @throws
     * @author gatsby
     * @since 2022/10/12 21:34
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object proceed = pjp.proceed();

        MarketLog marketLog = saveLog(pjp, proceed);
        if (marketLog != null){
            adminLogService.insertLog(marketLog);
        }
        return proceed;
    }

    /**
     * @description 保存日志，admin用户名等待从session调用
     * @param pjp
     * @return MarketLog
     * @throws
     * @author gatsby
     * @since 2022/10/13 10:49
     */
    public MarketLog saveLog(ProceedingJoinPoint pjp, Object proceed) throws NoSuchMethodException {
        MarketLog marketLog = null;
        Signature signature = pjp.getSignature();
        Class<?> aClass = pjp.getTarget().getClass();
        //获取目标类方法
        Method method = ((MethodSignature) signature ).getMethod();
        //这个方法才是目标对象上有注解的方法
        Method realMethod = pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());

        boolean methodPost = realMethod.isAnnotationPresent(PostMapping.class);
        boolean methodGet = realMethod.isAnnotationPresent(GetMapping.class);

        if (methodGet || methodPost){
            String[] value1 = null;
            String[] value2 = null;
            RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
            value1 = annotation.value();
            if (methodPost){
                PostMapping an = realMethod.getAnnotation(PostMapping.class);
                value2 = an.value();
            } else if (methodGet){
                GetMapping an = realMethod.getAnnotation(GetMapping.class);
                value2 = an.value();
            }

            /**
             * type = 0 一般操作
             * type = 1 安全操作
             * type = 2 订单操作
             * type = 3 其他操作
             **/
            if ("admin/auth".equals(value1[0])){
                marketLog = getCommonMarketLog(proceed);
                marketLog.setType(1);
                if ("login".equals(value2[0])){
                    marketLog.setAction("登录");
                } else if ("logout".equals(value2[0])){
                    marketLog.setAction("退出");
                } else {
                    marketLog = null;
                }
            }
            if ("admin/admin".equals(value1[0])){
                marketLog = getCommonMarketLog(proceed);
                marketLog.setType(1);
                if ("create".equals(value2[0])){
                    marketLog.setAction("添加管理员");
                    Object[] args = pjp.getArgs();
                    marketLog.setResult(((MarketAdmin)args[0]).getUsername());
                } else if ("update".equals(value2[0])){
                    marketLog.setAction("更新管理员");
                    Object[] args = pjp.getArgs();
                    marketLog.setResult(((MarketAdmin)args[0]).getUsername());
                } else if ("delete".equals(value2[0])){
                    marketLog.setAction("删除管理员");
                    Object[] args = pjp.getArgs();
                    marketLog.setResult(((MarketAdmin)args[0]).getUsername());
                } else{
                    marketLog = null;
                }
            }
            if ("admin/order".equals(value1[0])){
                marketLog = getCommonMarketLog(proceed);
                marketLog.setType(2);
                if ("ship".equals(value2[0])){
                    marketLog.setAction("发货");
                    Object[] args = pjp.getArgs();
                    //Integer id = (Integer) ((Map)args[0]).get("orderId");
                    Integer id = ((AdminOrderShipBO) args[0]).getOrderId();
                    String orderSn = adminLogService.queryOrderSnById(id);
                    marketLog.setResult("订单编号：" + orderSn);
                } else if ("refund".equals(value2[0])){
                    marketLog.setAction("退款");
                    Object[] args = pjp.getArgs();
                    //Integer id = (Integer) ((Map)args[0]).get("orderId");
                    Integer id = ((AdminOrderShipBO) args[0]).getOrderId();
                    String orderSn = adminLogService.queryOrderSnById(id);
                    marketLog.setResult("订单编号：" + orderSn);
                } else if ("delete".equals(value2[0])){
                    marketLog.setAction("删除");
                    Object[] args = pjp.getArgs();
                    //Integer id = (Integer) ((Map)args[0]).get("orderId");
                    Integer id = ((AdminOrderShipBO) args[0]).getOrderId();
                    String orderSn = adminLogService.queryOrderSnById(id);
                    marketLog.setResult("订单编号：" + orderSn);
                } else{
                    marketLog = null;
                }
            }
        }
        return marketLog;
    }


    public  String getIpAdrress(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if ("127.0.0.1".equals(ipAddress) || "0:0:0:0:0:0:0:1".equals(ipAddress)) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (Exception e) {
                    //log.error("根据网卡获取本机配置的IP异常=>", e.getMessage());
                    e.printStackTrace();
                }
                if (inet.getHostAddress() != null) {
                    ipAddress = inet.getHostAddress();
                }
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) {
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }
    /**
     * @description 获得一个有相同信息的MarketLog实例
     * @param proceed
     * @return MarketLog
     * @throws
     * @author Gaojinman
     * @since 2022/10/13 20:01
     */
    public MarketLog getCommonMarketLog(Object proceed){
        MarketLog marketLog = new MarketLog();
        BaseRespVo baseRespVo = (BaseRespVo) proceed;
        Date date = new Date();
        marketLog.setAddTime(date);
        marketLog.setUpdateTime(date);
        marketLog.setStatus(true);
        //controller 相应一个失败信息
        if (baseRespVo.getErrno() != 0){
            marketLog.setStatus(false);
        }
        //2022/10/13 admin用户名从session调用 登陆失败时无法从session获得数据
        //605 登陆失败
        if (baseRespVo.getErrno() != 605){
            Subject subject = SecurityUtils.getSubject();
            MarketAdmin marketAdmin= (MarketAdmin) subject.getPrincipal();
            marketLog.setAdmin(marketAdmin.getUsername());
        } else {
            marketLog.setAdmin("匿名用户");
        }

        // 获取请求信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 获取请求用户IP


        String userIp = getIpAdrress(request);
        marketLog.setIp(userIp);
        return marketLog;
    }
}
